using System;
using System.Collections;
using System.Reflection;
using System.Xml.Schema;

namespace Vibstudio.X4NET.Xml.Generation
{
    internal enum XmlSchemaWhiteSpace
    {
        Preserve,

        Replace,

        Collapse,
    }

    [Flags]
    internal enum RestrictionFlags
    {
        Length = 0x0001,

        MinLength = 0x0002,

        MaxLength = 0x0004,

        Pattern = 0x0008,

        Enumeration = 0x0010,

        WhiteSpace = 0x0020,

        MaxInclusive = 0x0040,

        MaxExclusive = 0x0080,

        MinInclusive = 0x0100,

        MinExclusive = 0x0200,

        TotalDigits = 0x0400,

        FractionDigits = 0x0800,
    }

    internal class CompiledFacets
    {
        public static readonly Type XsdSimpleValueType;

        private static readonly FieldInfo lengthInfo;
        private static readonly FieldInfo minLengthInfo;
        private static readonly FieldInfo maxLengthInfo;
        private static readonly FieldInfo patternsInfo;
        private static readonly FieldInfo enumerationInfo;
        private static readonly FieldInfo whitespaceInfo;
        private static readonly FieldInfo maxInclusiveInfo;
        private static readonly FieldInfo maxExclusiveInfo;
        private static readonly FieldInfo minInclusiveInfo;
        private static readonly FieldInfo minExclusiveInfo;
        private static readonly FieldInfo totalDigitsInfo;
        private static readonly FieldInfo fractionDigitsInfo;
        private static readonly FieldInfo restrictionFlagsInfo;
        private static readonly FieldInfo restrictionFixedFlagsInfo;

        private readonly object _compiledRestriction;


        static CompiledFacets()
        {
            Assembly systemXmlAsm = typeof(XmlSchema).Assembly;

            Type restrictionFacetsType = systemXmlAsm.GetType("System.Xml.Schema.RestrictionFacets", true);
            XsdSimpleValueType = systemXmlAsm.GetType("System.Xml.Schema.XsdSimpleValue", true);

            lengthInfo = restrictionFacetsType.GetField("Length", BindingFlags.Instance | BindingFlags.NonPublic);
            minLengthInfo = restrictionFacetsType.GetField("MinLength", BindingFlags.Instance | BindingFlags.NonPublic);
            maxLengthInfo = restrictionFacetsType.GetField("MaxLength", BindingFlags.Instance | BindingFlags.NonPublic);
            patternsInfo = restrictionFacetsType.GetField("Patterns", BindingFlags.Instance | BindingFlags.NonPublic);
            enumerationInfo = restrictionFacetsType.GetField("Enumeration", BindingFlags.Instance | BindingFlags.NonPublic);
            whitespaceInfo = restrictionFacetsType.GetField("WhiteSpace", BindingFlags.Instance | BindingFlags.NonPublic);
            maxInclusiveInfo = restrictionFacetsType.GetField("MaxInclusive", BindingFlags.Instance | BindingFlags.NonPublic);
            maxExclusiveInfo = restrictionFacetsType.GetField("MaxExclusive", BindingFlags.Instance | BindingFlags.NonPublic);
            minInclusiveInfo = restrictionFacetsType.GetField("MinInclusive", BindingFlags.Instance | BindingFlags.NonPublic);
            minExclusiveInfo = restrictionFacetsType.GetField("MinExclusive", BindingFlags.Instance | BindingFlags.NonPublic);
            totalDigitsInfo = restrictionFacetsType.GetField("TotalDigits", BindingFlags.Instance | BindingFlags.NonPublic);
            fractionDigitsInfo = restrictionFacetsType.GetField("FractionDigits", BindingFlags.Instance | BindingFlags.NonPublic);
            restrictionFlagsInfo = restrictionFacetsType.GetField("Flags", BindingFlags.Instance | BindingFlags.NonPublic);
            restrictionFixedFlagsInfo = restrictionFacetsType.GetField("FixedFlags", BindingFlags.Instance | BindingFlags.NonPublic);
        }

        public CompiledFacets(object restriction)
        {
            _compiledRestriction = restriction;
        }

        public int Length
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return 0;
                }
                return (int)lengthInfo.GetValue(_compiledRestriction);
            }
        }

        public int MinLength
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return 0;
                }
                return (int)minLengthInfo.GetValue(_compiledRestriction);
            }
        }

        public int MaxLength
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return 0;
                }
                return (int)maxLengthInfo.GetValue(_compiledRestriction);
            }
        }

        public ArrayList Patterns
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return null;
                }
                return (ArrayList)patternsInfo.GetValue(_compiledRestriction);
            }
        }

        public ArrayList Enumeration
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return null;
                }
                return (ArrayList)enumerationInfo.GetValue(_compiledRestriction);
            }
        }

        public XmlSchemaWhiteSpace WhiteSpace
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return XmlSchemaWhiteSpace.Preserve;
                }
                return (XmlSchemaWhiteSpace)whitespaceInfo.GetValue(_compiledRestriction);
            }
        }

        public object MaxInclusive
        {
            get
            {
                return _compiledRestriction == null ? null : maxInclusiveInfo.GetValue(_compiledRestriction);
            }
        }

        public object MaxExclusive
        {
            get
            {
                return _compiledRestriction == null ? null : maxExclusiveInfo.GetValue(_compiledRestriction);
            }
        }

        public object MinInclusive
        {
            get
            {
                return _compiledRestriction == null ? null : minInclusiveInfo.GetValue(_compiledRestriction);
            }
        }

        public object MinExclusive
        {
            get
            {
                return _compiledRestriction == null ? null : minExclusiveInfo.GetValue(_compiledRestriction);
            }
        }

        public int TotalDigits
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return 0;
                }
                return (int)totalDigitsInfo.GetValue(_compiledRestriction);
            }
        }

        public int FractionDigits
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return 0;
                }
                return (int)fractionDigitsInfo.GetValue(_compiledRestriction);
            }
        }

        public RestrictionFlags Flags
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return 0;
                }
                return (RestrictionFlags)restrictionFlagsInfo.GetValue(_compiledRestriction);
            }
        }

        public RestrictionFlags FixedFlags
        {
            get
            {
                if (_compiledRestriction == null)
                {
                    return 0;
                }
                return (RestrictionFlags)restrictionFixedFlagsInfo.GetValue(_compiledRestriction);
            }
        }
    }
}